package com.wxl.micro.service.gateway.predicates;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import javax.validation.constraints.NotEmpty;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

/**
 *
 * 断言工厂: 解决是不是、有没有、在不在等问题
 * 自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类，重写 apply 方法的逻辑。在 apply 方法中可以通过
 * exchange.getRequest() 拿到 ServerHttpRequest 对象，从而可以获取到请求的参数、请求方式、请求头等信息。
 * 1、 必须spring组件 bean
 * 2. 类必须加上RoutePredicateFactory作为结尾
 * 3. 必须继承AbstractRoutePredicateFactory
 * 4. 必须声明静态内部类 声明属性来接收 配置文件中对应的断言的信息
 * 5. 需要结合shortcutFieldOrder进行绑定
 * 6.通过apply进行逻辑判断 true就是匹配成功 false匹配失败
 */

@Component // 是个bean
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {

    public static final String AUTH_KEY = "auth";
    public static final List<String> SESSION_DB = Arrays.asList("aaa","bbb","ccc");

    public CheckAuthRoutePredicateFactory() {
        super(CheckAuthRoutePredicateFactory.Config.class);
    }

    public List<String> shortcutFieldOrder() {
        return Arrays.asList(AUTH_KEY);
    }

    public Predicate<ServerWebExchange> apply(CheckAuthRoutePredicateFactory.Config config) {

        return new GatewayPredicate() {
            public boolean test(ServerWebExchange exchange) {

                if(StringUtils.isEmpty(config.auth)){
                    return false;
                }

                List<String> values = (List)exchange.getRequest().getHeaders().getOrDefault(config.auth, Collections.emptyList());
                if (values.isEmpty()) {
                    return false;
                }

                String currAuth =  values.get(0);

                // 可以check auth
                if(SESSION_DB.contains(currAuth)){
                    // 如果header中有auth=session,就通过
                    return true;
                }

                return false;
            }

            public String toString() {
                return String.format("Header: %s", config.auth);
            }
        };
    }

    @Validated
    public static class Config {
        @NotEmpty
        private String auth;

        public Config() {
        }

        public String getAuth() {
            return auth;
        }

        public void setAuth(String auth) {
            this.auth = auth;
        }
    }
}
